﻿
// CClient.cpp: 定义应用程序的类行为。
//

#include "pch.h"
#include "framework.h"
#include "CClient.h"
#include "CMainDlg.h"
#include "CLoginDlg.h"
#include "CNodeDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CClient

BEGIN_MESSAGE_MAP(CClient, CWinApp)
	ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()


// CClient 构造

CClient::CClient()
{
	// 支持重新启动管理器
	m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;
}


// 唯一的 CClient 对象

CClient theApp;


// CClient 初始化

BOOL CClient::InitInstance()
{
	// 如果下面的注释掉，注册表为NULL，会从INI文件中读，INI文件默认在Windows目录下
	// 注册表路径 HKEY_CURRENT_USER\SOFTWARE
	// SetRegistryKey(_T("ZCYID"));// 公司名或产品写入
	// 修改INI文件的路径
	if (m_pszProfileName) {
		free((void*)m_pszProfileName);
	}
	LPTSTR p = (LPTSTR)malloc(32 * sizeof(TCHAR));
	if (p) {
		_tcscpy_s(p, 32, _T(".\\Client.ini"));
		m_pszProfileName = p;
	}
	// 上面简写的方式
	// m_pszProfileName = _tcsdup(_T(".\\Client.ini"));

	// 获取exe路径
	TCHAR s[MAX_PATH];
	GetModuleFileName(m_hInstance, s, MAX_PATH);

	// 获取命令行参数，cmd中添加 或 属性->调试->命令参数
	TRACE(theApp.m_lpCmdLine);
	// socket初始化
	AfxSocketInit();
	
	CString cmd = theApp.m_lpCmdLine;
	if (!cmd.IsEmpty()) {
		AfxMessageBox(theApp.m_lpCmdLine);
		CNodeDlg node;
		node.DoModal();
		return FALSE;
	}

	CLoginDlg lg;
	if (lg.DoModal() == IDCANCEL) {
		return FALSE;
	}
	CMainDlg dlg;
	dlg.DoModal();
	return FALSE;
}


std::string CClient::UnicodeToUTF8(const wchar_t* str)
{
	// WideChar 宽 -> MultiByte 多
	// 计算所需长度
	int n = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
	auto p = new char[n + 1];
	// 目标空间和长度
	n = WideCharToMultiByte(CP_UTF8, 0, str, -1, p, n, NULL, NULL);
	p[n] = 0;
	std::string s(p);
	delete[] p;
	return s;
}

CString CClient::UTF8ToUnicode(const char* str)
{
	int n = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
	auto p = new wchar_t[n + 1];
	n = MultiByteToWideChar(CP_UTF8, 0, str, -1, p, n);
	p[n] = 0;
	CString c(p);
	delete[] p;
	return c;
}

BOOL CClient::sockeInit()
{
	if (m_sock.m_hSocket != INVALID_SOCKET) {
		AfxMessageBox(_T("socket 有效"));// 如果服务器断开，则需要心跳检查，可以通过sock.Close(); 之后重新Create
		return TRUE;
	}
	try {
		// 创建socket
		if (!m_sock.Create()) {
			MessageBox(NULL, _T("Socket创建失败"), _T("提示"), MB_OK | MB_ICONERROR);
			return FALSE;
		}
		// 连接服务器
		if (!m_sock.Connect(_T("127.0.0.1"), SERVER_PORT)) {
			MessageBox(NULL, _T("服务器连接失败"), _T("提示"), MB_OK | MB_ICONERROR);
			return FALSE;
		}
	}
	catch (CException* e) {// 默认捕获没生效
		CString strError;
		e->GetErrorMessage(strError.GetBufferSetLength(256), 256);
		strError.ReleaseBuffer();
		AfxMessageBox(strError);
		e->Delete();
	}
}

// UTF8 无BOM规则
// 1. 一个字符 0x00 - 0x7F
// 2. 多个字符 每个字节最高位都是1
//    2个字节 110x xxxx 10xx xxxx 
//    3个字节 1110 xxxx 10xx xxxx 10xx xxxx
//    4个字节 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx
BOOL CClient::CheckUtf8(LPCSTR p)
{
	while (*p) {
		BYTE c = *p;
		// 单字节的情况
		if (c >= 0x00 && c <= 0x7F) {
			p++;
			continue;
		}
		// 多字节的情况
		BYTE x = 0x80;
		int n = 0;
		while ((c & x) == x) {
			x >>= 1;// 1000 0000 - > 0100 0000
			n++;
		}
		if (n < 2 || n > 4) {
			return FALSE;
		}
		int step = n;
		while (--n) {
			c = *(p + 1);
			if ((c >> 6) != 0b10) {// 1000 0000 -> 0000 0010 
				return FALSE;
			}
			p++;
		}
		p++;
	}
	return TRUE;
}

// 大小端转换
void CClient::ConvertBig(LPSTR p)
{
	while (*(WORD*)p) {
		*p = *p ^ p[1];
		p[1] = *p ^ p[1];
		*p = *p ^ p[1];
		p += 2;
	}
}

char* CClient::CStringToPChar(CString str)
{
	int len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
	auto p = new char[len + 2];
	WideCharToMultiByte(CP_ACP, 0, str, -1, p, len, NULL, NULL);
	p[len] = 0;
	p[len + 1] = 0;
	return p;
}

wchar_t* CClient::UTF8ToUTF16LE(const char* str)
{
	int n = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
	auto p = new wchar_t[n + 1];
	n = MultiByteToWideChar(CP_UTF8, 0, str, -1, p, n);
	p[n] = 0;
	return p;
}

wchar_t* CClient::ANSIToUTF16LE(const char* str)
{
	int n = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
	auto p = new wchar_t[n + 1];
	MultiByteToWideChar(CP_ACP, 0, str, -1, p, n);
	return p;
}

char* CClient::UTF16LEToANSI(const wchar_t* str)
{
	int len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
	auto p = new char[len + 1];
	WideCharToMultiByte(CP_ACP, 0, str, -1, p, len, NULL, NULL);
	p[len] = 0;
	return p;
}

char* CClient::UTF16LEToUTF8(const wchar_t* str)
{
	// WideChar 宽 -> MultiByte 多
	// 计算所需长度
	int n = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
	auto p = new char[n + 1];
	// 目标空间和长度
	n = WideCharToMultiByte(CP_UTF8, 0, str, -1, p, n, NULL, NULL);
	p[n] = 0;
	return p;
}
